using System;
using System.Data;
using System.Data.SqlClient;

using BO = PHSRAG.Insight21.BusinessObjects;
using Utility = PHSRAG.Utility;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using GenerateKey = PHSRAG.Insight21.BusinessObjects.ModuleKey;

namespace PHSRAG.Insight21.Admin
{
	/// <summary>
	/// ApplicationUser is a business object that is tightly associated with a 
	/// row in the FwkApplicationUser table in the database.  It is a representation
	/// of an Insight application user and indicates the module(s), module role(s),
	/// and registration status of the application user.  If there is no row in the
	/// FwkApplicationUser table for a given domain user, that means that the domain
	/// user has never been registered for the Insight application.
	/// </summary>
	public class ApplicationUser: BO.SaveableBusinessObject
	{
		#region Constants
		private const string ApplicationUserTableName = "ApplicationUser";
		private static string ApplicationUserKey = GenerateKey.MakeKey("ApplicationUser_61E2D848-6E4C-4355-9A54-42E3D7053FC9",GenerateKey.Admin);
		#endregion

		#region Instance Variables
		private SqlCommand	updateCommand;
		#endregion

		#region Public Properties
		/// <summary>
		/// Gets the application user's ModuleBitmask which holds bitvalues of modules 
		/// that the user has access to.
		/// </summary>
		public int ModuleBitMask
		{
			get 
			{
				int moduleBitMask = 0;
				if (DataContainer.Tables[ApplicationUserTableName].Rows.Count > 0 )
				{
					object o = DataContainer.Tables[ApplicationUserTableName].Rows[0]["ModuleBitMask"];
					moduleBitMask = (o == DBNull.Value) ? 0 : (int)o;
				}
				return moduleBitMask;
			}
		}
		#endregion

		#region Constructor
		/// <summary>
		/// Initialize the state of this object and creates commands to handle updating of application user data.
		/// </summary>
		public ApplicationUser( ICachePolicy cachePolicy) : base(cachePolicy)
		{
			DataContainer = new DataSet();
			CreateCommands();
		}
		#endregion

		#region Base Methods
		/// <summary>Caches this object based on it's caching policy.</summary>
		public override void Cache()
		{
			CachePolicy.Cache(ApplicationUserKey, this);
		}

		/// <summary>UnCaches this object based on it's caching policy.</summary>
		public override void UnCache()
		{
			CachePolicy.UnCache(ApplicationUserKey);
		}

		/// <summary>
		/// Expects a valid domain user id to be used to load this application user object's
		/// DataContainer by calling the GetApplicationUser stored procedures in the database.
		/// If there is not an entry for a domain user in the application user table, that is 
		/// acceptible and simply means that the user has never been registered for the application.
		/// If a domain user id is not specified an Exception is thrown. 
		/// </summary>
		/// <param name="connectionString">Valid database connection string.</param>
		/// <param name="args">The domain user id to be used to load the application user object.</param>
		public override void Load( string connectionString, params object[] args )
		{
			if ( args.Length != 1 )
			{
				throw new Exception ("Application User Load expects Person ID." );
			}

			int domainUserId = (int)args[0];

			try
			{
				Utility.DataAccess.LoadDataSet(DataContainer, ApplicationUserTableName, connectionString,
					"GetApplicationUser", Utility.DataAccess.BuildSqlParameterArray("@domainUserId" ,SqlDbType.Int, domainUserId));
			}
			catch( Exception e)
			{
				Utility.ExceptionReport.WriteToEventLog ("Application User", e, true, Utility.ExceptionReport.ReportType.Error);
			}
		}

		/// <summary>
		/// Persists ApplicationUser state to the database.
		/// </summary>
		/// <param name="connectionString">Specifies database connection information.</param>
		public override void Save(string connectionString, params object[] args)
		{
			SqlConnection connection = new SqlConnection(connectionString);
			try
			{
				connection.Open();
				ExecuteUpdate(connection);
			}
			finally
			{
				if (connection.State != ConnectionState.Closed)
					connection.Close();
			}
		}
		#endregion

		#region Private Methods
		/// <summary>
		/// We never delete application user entries in the database, only insert new and update  
		/// existing rows.Create the set of SqlCommand objects used for the insertion, and updates 
		/// made on the associated DataTable.  Notice that each command is initialized to invoke a stored
		/// procedure implying that each command may have its own set of parameters in line with that
		/// stored procedure.
		/// </summary>
		private void CreateCommands()
		{
			updateCommand = new SqlCommand();
			updateCommand.CommandText = "SetApplicationUser";
			updateCommand.CommandType = CommandType.StoredProcedure;
			updateCommand.CommandTimeout = Convert.ToInt32(Utility.Settings.GetKeyValue("Database.Insight.CommandTimeout", "0"));
			updateCommand.Parameters.Add("@applicationBitmask", SqlDbType.Int).SourceColumn = "ApplicationBitmask";
			updateCommand.Parameters.Add("@isActiveBitmask", SqlDbType.Int).SourceColumn = "IsActiveBitmask";
			updateCommand.Parameters.Add("@domainUserId", SqlDbType.Int).SourceColumn = "FwkDomainUserId";
			updateCommand.Parameters.Add("@moduleBitmask", SqlDbType.Int).SourceColumn = "ModuleBitmask";
			updateCommand.Parameters.Add("@moduleRoleBitmask", SqlDbType.Int).SourceColumn = "ModuleRoleBitmask";
		}

		private void ExecuteUpdate(SqlConnection connection)
		{
			SqlDataAdapter adapter = new SqlDataAdapter();
			updateCommand.Connection = connection;				
			adapter.InsertCommand = updateCommand;
			adapter.UpdateCommand = updateCommand;
			adapter.Update(DataContainer, ApplicationUserTableName);
		}
			

		#endregion

	}
}
